﻿using AKBGame.Constant;
using AKBGame.Object;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AKBGame.Service
{
    public class EventCalculator
    {
        public List<LevelExperience> LevelExperienceList { get; set; }

        public EventCalculator(List<LevelExperience> levelExperienceList)
        {
            this.LevelExperienceList = levelExperienceList;
        }

        public List<EventCalculation> CalculateTotalPoint(int currentAKBPoint, int currentSKEPoint, int currentNMBPoint, int currentHKTPoint, int currentLP, int currentLevel, int currentExp, DateTime currentDateTime, int targetTotalPoint, EventGameDetail eventGameDetail)
        {
            List<EventCalculation> eventCalculationList = CalculateStrategyTotal(currentLP, currentLevel, currentExp, currentDateTime, eventGameDetail, currentAKBPoint, currentSKEPoint, currentNMBPoint, currentHKTPoint, targetTotalPoint);
            return eventCalculationList;
        }

        private List<EventCalculation> CalculateStrategyTotal(int currentLP, int currentLevel, int currentExp, DateTime currentDateTime, EventGameDetail eventGameDetail, int currentAKBPoint, int currentSKEPoint, int currentNMBPoint, int currentHKTPoint, int targetPoint)
        {
            List<EventCalculation> eventCalculationList = new List<EventCalculation>();

            DifficultyPoint bestDifficultyPoint = eventGameDetail.FindBestDifficultyPoint(currentExp, currentLP);
            DifficultyExpLP bestDifficultyExpLP = eventGameDetail.DifficultyExpLPList.Single(o => o.Difficulty == bestDifficultyPoint.Difficulty);
            int currentPoint = currentAKBPoint + currentSKEPoint + currentNMBPoint + currentHKTPoint;

            while (currentPoint < targetPoint)
            {
                if (currentLP >= bestDifficultyExpLP.LP)
                {
                    EventCalculation eventCalculation = new EventCalculation();
                    eventCalculation.EventDate = currentDateTime.AddMinutes(3);

                    eventCalculation.TotalPoint = currentPoint += bestDifficultyPoint.Point;

                    if(bestDifficultyPoint.Mode == GroupName.AKB)
                        eventCalculation.AKBPoint = currentAKBPoint += bestDifficultyPoint.Point;
                    else if (bestDifficultyPoint.Mode == GroupName.SKE)
                        eventCalculation.SKEPoint = currentSKEPoint += bestDifficultyPoint.Point;
                    else if (bestDifficultyPoint.Mode == GroupName.NMB)
                        eventCalculation.NMBPoint = currentNMBPoint += bestDifficultyPoint.Point;
                    else if (bestDifficultyPoint.Mode == GroupName.HKT)
                        eventCalculation.HKTPoint = currentHKTPoint += bestDifficultyPoint.Point;

                    eventCalculation.Difficulty = bestDifficultyExpLP.Difficulty;

                    if (currentExp <= bestDifficultyExpLP.Exp)
                    {
                        eventCalculation.Level = ++currentLevel;
                        eventCalculation.RemainExp = currentExp = LevelExperienceList.Single(o => o.Level == eventCalculation.Level).Experience + currentExp - bestDifficultyExpLP.Exp;
                        eventCalculation.LP = currentLP = LevelExperienceList.Single(o => o.Level == eventCalculation.Level).LP;
                    }

                    else
                    {
                        eventCalculation.Level = currentLevel;
                        eventCalculation.RemainExp = currentExp -= bestDifficultyExpLP.Exp;
                        eventCalculation.LP = currentLP = currentLP - bestDifficultyExpLP.LP;
                    }

                    eventCalculationList.Add(eventCalculation);
                }

                else
                {
                    EventCalculation eventCalculation = new EventCalculation();

                    eventCalculation.TotalPoint = currentPoint;

                    if (bestDifficultyPoint.Mode == GroupName.AKB)
                        eventCalculation.AKBPoint = currentAKBPoint;
                    else if (bestDifficultyPoint.Mode == GroupName.SKE)
                        eventCalculation.SKEPoint = currentSKEPoint;
                    else if (bestDifficultyPoint.Mode == GroupName.NMB)
                        eventCalculation.NMBPoint = currentNMBPoint;
                    else if (bestDifficultyPoint.Mode == GroupName.HKT)
                        eventCalculation.HKTPoint = currentHKTPoint;

                    eventCalculation.Difficulty = "Restore";
                    eventCalculation.Level = currentLevel;
                    eventCalculation.RemainExp = currentExp;

                    int maxRestoreTime = LevelExperienceList.Single(o => o.Level == eventCalculation.Level).LP / bestDifficultyExpLP.LP;

                    int currExp = currentExp;
                    int restoreTime = 0;
                    int restoreLP = 0;

                    while (currExp >= bestDifficultyExpLP.Exp)
                    {
                        currExp -= bestDifficultyExpLP.Exp;
                        restoreTime++;
                    }

                    if (currExp != 0 && currExp < bestDifficultyExpLP.Exp)
                        restoreTime++;

                    if (restoreTime <= maxRestoreTime)
                        restoreLP = bestDifficultyExpLP.LP * restoreTime - currentLP;

                    else
                        restoreLP = bestDifficultyExpLP.LP * maxRestoreTime - currentLP;

                    eventCalculation.LP = currentLP += restoreLP;
                    eventCalculation.EventDate = currentDateTime = currentDateTime.AddMinutes(4 * restoreLP);


                    eventCalculationList.Add(eventCalculation);
                }
            }

            return eventCalculationList;
        }

        private static void FindBestDifficultyTotal(int currentExp, int currentLP, EventGameDetail eventTotalGameDetail, ref int bestLP, ref int bestExp, ref int bestPoint, ref string bestMode, ref string bestDifficulty)
        {
            //double bestRatio = 0;

            //double hSRatio = 0;
            //double hardRatio = 0;
            //double normalRatio = 0;
            //double easyRatio = 0;

            ////HS
            //int maxHSPoint = Math.Max(Math.Max(eventTotalGameDetail.AKBPoint.HSPoint, eventTotalGameDetail.SKEPoint.HSPoint), Math.Max(eventTotalGameDetail.NMBPoint.HSPoint, eventTotalGameDetail.HKTPoint.HSPoint));

            //if (currentExp <= eventTotalGameDetail.HSExp && currentLP > eventTotalGameDetail.HSLP)
            //    hSRatio = maxHSPoint / currentLP;

            //else
            //    hSRatio = maxHSPoint / eventTotalGameDetail.HSLP;

            ////Hard
            //int maxHardPoint = Math.Max(Math.Max(eventTotalGameDetail.AKBPoint.HardPoint, eventTotalGameDetail.SKEPoint.HardPoint), Math.Max(eventTotalGameDetail.NMBPoint.HardPoint, eventTotalGameDetail.HKTPoint.HardPoint));

            //if (currentExp <= eventTotalGameDetail.HardExp && currentLP > eventTotalGameDetail.HardLP)
            //    hardRatio = maxHardPoint / currentLP;

            //else
            //    hardRatio = maxHardPoint / eventTotalGameDetail.HardLP;

            ////Normal
            //int maxNormalPoint = Math.Max(Math.Max(eventTotalGameDetail.AKBPoint.NormalPoint, eventTotalGameDetail.SKEPoint.NormalPoint), Math.Max(eventTotalGameDetail.NMBPoint.NormalPoint, eventTotalGameDetail.HKTPoint.NormalPoint));

            //if (currentExp <= eventTotalGameDetail.NormalExp && currentLP > eventTotalGameDetail.NormalLP)
            //    normalRatio = maxNormalPoint / currentLP;

            //else
            //    normalRatio = maxNormalPoint / eventTotalGameDetail.NormalLP;

            ////Easy
            //int maxEasyPoint = Math.Max(Math.Max(eventTotalGameDetail.AKBPoint.EasyPoint, eventTotalGameDetail.SKEPoint.EasyPoint), Math.Max(eventTotalGameDetail.NMBPoint.EasyPoint, eventTotalGameDetail.HKTPoint.EasyPoint));

            //if (currentExp <= eventTotalGameDetail.EasyExp && currentLP > eventTotalGameDetail.EasyLP)
            //    easyRatio = maxEasyPoint / currentLP;

            //else
            //    easyRatio = maxEasyPoint / eventTotalGameDetail.EasyLP;

            //double maxRatio = Math.Max(Math.Max(hSRatio, hardRatio), Math.Max(normalRatio, easyRatio));
            //bestRatio = maxRatio;

            //if (hSRatio == maxRatio)
            //{
            //    bestDifficulty = "HS";
            //    bestLP = eventTotalGameDetail.HSLP;
            //    bestExp = eventTotalGameDetail.HSExp;
            //    bestPoint = maxHSPoint;
            //}
        }

        public List<EventCalculation> CalculateGroupPoint(int currentAKBPoint, int currentSKEPoint, int currentNMBPoint, int currentHKTPoint, 
            int currentLP, int currentLevel, int currentExp, DateTime currentDateTime, 
            int targetAKBPoint, int targetSKEPoint, int targetNMBPoint, int targetHKTPoint, EventGameDetail eventGameDetail)
        {
            List<EventCalculation> eventCalculationList = new List<EventCalculation>();

            //int bestLP = 0;
            //int bestExp = 0;
            //int bestPoint = 0;
            //string bestDifficulty = "";

            //EventCalculation initialStatus = new EventCalculation();
            //initialStatus.Level = currentLevel;
            //initialStatus.EventDate = currentDateTime;
            //initialStatus.LP = currentLP;
            //initialStatus.RemainExp = currentExp;
            //initialStatus.AKBPoint = currentAKBPoint;
            //initialStatus.SKEPoint = currentSKEPoint;
            //initialStatus.NMBPoint = currentNMBPoint;
            //initialStatus.HKTPoint = currentHKTPoint;
            //initialStatus.Difficulty = "Initial";
            //eventCalculationList.Add(initialStatus);

            //while (currentAKBPoint < targetAKBPoint || currentSKEPoint < targetSKEPoint || currentNMBPoint < targetNMBPoint || currentHKTPoint < targetHKTPoint)
            //{
            //    EventGameDetailPoint eventGameDetailPoint = null;

            //    if (currentAKBPoint < targetAKBPoint)
            //    {
            //        eventGameDetailPoint = eventGameDetail.AKBPoint;
            //        CalculateStrategy(ref currentLP, ref currentLevel, ref currentExp, ref currentDateTime, eventGameDetail, eventCalculationList, ref bestLP, ref bestExp, ref bestPoint, ref bestDifficulty, ref currentAKBPoint, targetAKBPoint, eventGameDetailPoint, "AKB");
            //    }

            //    else if (currentSKEPoint < targetSKEPoint)
            //    {
            //        eventGameDetailPoint = eventGameDetail.SKEPoint;
            //        CalculateStrategy(ref currentLP, ref currentLevel, ref currentExp, ref currentDateTime, eventGameDetail, eventCalculationList, ref bestLP, ref bestExp, ref bestPoint, ref bestDifficulty, ref currentSKEPoint, targetSKEPoint, eventGameDetailPoint, "SKE");
            //    }

            //    else if (currentNMBPoint < targetNMBPoint)
            //    {
            //        eventGameDetailPoint = eventGameDetail.NMBPoint;
            //        CalculateStrategy(ref currentLP, ref currentLevel, ref currentExp, ref currentDateTime, eventGameDetail, eventCalculationList, ref bestLP, ref bestExp, ref bestPoint, ref bestDifficulty, ref currentNMBPoint, targetNMBPoint, eventGameDetailPoint, "NMB");
            //    }

            //    else if (currentHKTPoint < targetHKTPoint)
            //    {
            //        eventGameDetailPoint = eventGameDetail.HKTPoint;
            //        CalculateStrategy(ref currentLP, ref currentLevel, ref currentExp, ref currentDateTime, eventGameDetail, eventCalculationList, ref bestLP, ref bestExp, ref bestPoint, ref bestDifficulty, ref currentHKTPoint, targetHKTPoint, eventGameDetailPoint, "HKT");
            //    }
            //}

            return eventCalculationList;
        }

        //private void CalculateStrategy(ref int currentLP, ref int currentLevel, ref int currentExp, ref DateTime currentDateTime, EventGameDetail eventGameDetail, List<EventCalculation> eventCalculationList, ref int bestLP, ref int bestExp, ref int bestPoint, ref string bestDifficulty, ref int currentPoint, int targetPoint, EventGameDetailPoint eventGameDetailPoint, string pointType)
        //{
        //    while (currentPoint < targetPoint)
        //    {
        //        FindBestDifficulty(currentExp, currentLP, eventGameDetail, eventGameDetailPoint, ref bestLP, ref bestExp, ref bestPoint, ref bestDifficulty);

        //        if (currentLP >= bestLP)
        //        {
        //            EventCalculation eventCalculation = new EventCalculation();
        //            eventCalculation.EventDate = currentDateTime;

        //            if(pointType == "Total") 
        //                eventCalculation.TotalPoint = currentPoint += bestPoint;
        //            else if (pointType == "AKB")
        //                eventCalculation.AKBPoint = currentPoint += bestPoint;
        //            else if (pointType == "SKE")
        //                eventCalculation.SKEPoint = currentPoint += bestPoint;
        //            else if (pointType == "NMB")
        //                eventCalculation.NMBPoint = currentPoint += bestPoint;
        //            else if (pointType == "HKT")
        //                eventCalculation.HKTPoint = currentPoint += bestPoint;

        //            eventCalculation.Difficulty = bestDifficulty;

        //            if (currentExp <= bestExp)
        //            {
        //                eventCalculation.Level = ++currentLevel;
        //                eventCalculation.RemainExp = currentExp = LevelExperienceList.Single(o => o.Level == eventCalculation.Level).Experience + currentExp - bestExp;
        //                eventCalculation.LP = currentLP = LevelExperienceList.Single(o => o.Level == eventCalculation.Level).LP;
        //            }

        //            else
        //            {
        //                eventCalculation.Level = currentLevel;
        //                eventCalculation.RemainExp = currentExp -= bestExp;
        //                eventCalculation.LP = currentLP = currentLP - bestLP;
        //            }

        //            eventCalculationList.Add(eventCalculation);
        //        }

        //        else
        //        {
        //            EventCalculation eventCalculation = new EventCalculation();

        //            if (pointType == "Total")
        //                eventCalculation.TotalPoint = currentPoint;
        //            else if (pointType == "AKB")
        //                eventCalculation.AKBPoint = currentPoint;
        //            else if (pointType == "SKE")
        //                eventCalculation.SKEPoint = currentPoint;
        //            else if (pointType == "NMB")
        //                eventCalculation.NMBPoint = currentPoint;
        //            else if (pointType == "HKT")
        //                eventCalculation.HKTPoint = currentPoint;

        //            eventCalculation.Difficulty = "Restore";
        //            eventCalculation.Level = currentLevel;
        //            eventCalculation.RemainExp = currentExp;

        //            int maxRestoreTime = LevelExperienceList.Single(o => o.Level == eventCalculation.Level).LP / bestLP;

        //            int currExp = currentExp;
        //            int restoreTime = 0;
        //            int restoreLP = 0;

        //            while (currExp >= bestExp)
        //            {
        //                currExp -= bestExp;
        //                restoreTime++;
        //            }

        //            if (currExp != 0 && currExp < bestExp)
        //            {
        //                restoreTime++;
        //            }

        //            if (restoreTime <= maxRestoreTime)
        //            {
        //                restoreLP = bestLP * restoreTime - currentLP;
        //            }

        //            else
        //            {
        //                restoreLP = bestLP * maxRestoreTime - currentLP;
        //            }


        //            eventCalculation.LP = currentLP += restoreLP;
        //            eventCalculation.EventDate = currentDateTime = currentDateTime.AddMinutes(4 * restoreLP);


        //            eventCalculationList.Add(eventCalculation);
        //        }
        //    }
        //}

        //private static void FindBestDifficulty(int currentExp, int currentLP, EventGameDetail eventTotalGameDetail, EventGameDetailPoint eventGameDetailPoint, ref int bestLP, ref int bestExp, ref int bestPoint, ref string bestDifficulty)
        //{
        //    double bestRatio = 0;
        //    double difficultyRatio = 0;

        //    //HS
        //    if (currentExp <= eventTotalGameDetail.HSExp && currentLP > eventTotalGameDetail.HSLP)
        //    {
        //        difficultyRatio = eventGameDetailPoint.HSPoint / currentLP;
        //    }

        //    else
        //    {
        //        difficultyRatio = eventGameDetailPoint.HSPoint / eventTotalGameDetail.HSLP;
        //    }

        //    if (bestRatio <= difficultyRatio)
        //    {
        //        bestRatio = difficultyRatio;
        //        bestDifficulty = "HS";
        //        bestLP = eventTotalGameDetail.HSLP;
        //        bestExp = eventTotalGameDetail.HSExp;
        //        bestPoint = eventGameDetailPoint.HSPoint;
        //    }

        //    //Hard
        //    if (currentExp <= eventTotalGameDetail.HardExp && currentLP > eventTotalGameDetail.HardLP)
        //    {
        //        difficultyRatio = eventGameDetailPoint.HardPoint / currentLP;
        //    }

        //    else
        //    {
        //        difficultyRatio = eventGameDetailPoint.HardPoint / eventTotalGameDetail.HardLP;
        //    }

        //    if (bestRatio <= difficultyRatio)
        //    {
        //        bestRatio = difficultyRatio;
        //        bestDifficulty = "Hard";
        //        bestLP = eventTotalGameDetail.HardLP;
        //        bestExp = eventTotalGameDetail.HardExp;
        //        bestPoint = eventGameDetailPoint.HardPoint;
        //    }

        //    //Normal
        //    if (currentExp <= eventTotalGameDetail.NormalExp && currentLP > eventTotalGameDetail.NormalLP)
        //    {
        //        difficultyRatio = eventGameDetailPoint.NormalPoint / currentLP;
        //    }

        //    else
        //    {
        //        difficultyRatio = eventGameDetailPoint.NormalPoint / eventTotalGameDetail.NormalLP;
        //    }

        //    if (bestRatio <= difficultyRatio)
        //    {
        //        bestRatio = difficultyRatio;
        //        bestDifficulty = "Normal";
        //        bestLP = eventTotalGameDetail.NormalLP;
        //        bestExp = eventTotalGameDetail.NormalExp;
        //        bestPoint = eventGameDetailPoint.NormalPoint;
        //    }

        //    //Easy
        //    if (currentExp <= eventTotalGameDetail.EasyExp && currentLP > eventTotalGameDetail.EasyLP)
        //    {
        //        difficultyRatio = eventGameDetailPoint.EasyPoint / currentLP;
        //    }

        //    else
        //    {
        //        difficultyRatio = eventGameDetailPoint.EasyPoint / eventTotalGameDetail.EasyLP;
        //    }

        //    if (bestRatio <= difficultyRatio)
        //    {
        //        bestRatio = difficultyRatio;
        //        bestDifficulty = "Easy";
        //        bestLP = eventTotalGameDetail.EasyLP;
        //        bestExp = eventTotalGameDetail.EasyExp;
        //        bestPoint = eventGameDetailPoint.EasyPoint;
        //    }
        //}
    }
}
